<?php
/*
 * Clase para el trabajo con la BD Mysql.
 * usamos el driver MySQLi
 */

/**
 * Descripcion de classBD
 *
 * @author Jonas Reyes
 */
class BD {
    //Atributos de la Clase
    public $nombreServidorBD;
    public $nombreUsuarioBD;
    public $claveUsuarioBD;
    public $nombreBD;
    public $punteroBD; // muy importante esta variable, mantiene el link de la conexion establecida
    public $resultado;
    public $querys;
    public $array; // conserva en un array la ultima consulta.
    public $numFilas;
    public $numColumnas;
    public $setCharset;
    public $stmt_init;


    function __construct($Serv=SERV,$User=US_BD,$Pass=US_PASS,$Bd=NOM_BD){
        $this->SetNombreServidorBD($Serv);
        $this->SetNombreUsuarioBD($User);
        $this->SetClaveBD($Pass);
        $this->SetNombreBD($Bd);
        if ($this->Conectar()) {
            return true;
        }else {
            return Core::MsgError("Error, no se pudo establecer la conexion con la Base de Datos.");
        }

    }

    function __destruct(){

    }

    public function stmt_init(){
        if ($var=$this->punteroBD->stmt_init()) {
            
            return $this->stmt_init;
        }
        return false;
    }

    public function SetNombreServidorBD($nombre=SERV){
        $this->nombreServidorBD=$nombre;
    }
    public function GetNombreServidorBD(){
        return $this->nombreServidorBD;
    }

    public function SetNombreUsuarioBD($usuario=US_BD){
        $this->nombreUsuarioBD=$usuario;
    }
    public function GetNombreUsuarioBD(){
        return $this->nombreUsuarioBD;
    }

    public function SetClaveBD($clave=US_PASS){
        $this->claveUsuarioBD=$clave;
    }
    public function GetClaveBD(){
        return $this->claveUsuarioBD;
    }

    public function SetNombreBD($nombreBD=NOM_BD){
        $this->nombreBD=$nombreBD;
    }
    public function GetNombreBD(){
        return $this->nombreBD;
    }

    public function Conectar($Serv=SERV,$User=US_BD,$Pass=US_PASS,$Bd=NOM_BD){
        @$this->punteroBD= new mysqli($Serv,$User,$Pass,$Bd);
        if (mysqli_connect_errno()) {
            return Core::MsgError("Error, ha fallado la conexion con mysql, "
                ."por favor verifique sus datos de conexion en el archivo "
                ."'configuracion/Configuracion.php'. "
                ."Error de MySQL: ".mysqli_connect_errno()." - ".mysqli_connect_error());
        }else {
            return true;
        }
    }//Fin del Metodo

    /**
     * Metodo que retorna el tipo de caracteres usados por defectos en la BD.
     */
    public function GetCharset(){
        $charset=$this->punteroBD->character_set_name();
        return $charset;
    }

    public function SetCharset($charset="utf8"){
        if (!Core::ValidacionBasica($charset)) {
            return Core::MsgError("Error, para poder usar el metodo 'SetCharset()'"
                ." debe definir el atributo \$charset.");
        }

        if (!$this->punteroBD->set_charset($charset)) {
            $this->setCharset="Error";
            return Core::MsgError("Error, metodo 'SetCharset()' no pudo definir"
                ." correctamente la codificacion '$charset' en la BD. "
                ."Mensaje de MySQL: ".$this->punteroBD->errno." - ".$this->punteroBD->error);
        }else {
            $this->setCharset=$charset;
            return true;
        }
    }

/**
 * Metodo que devuelve los resultados de una consulta en arrays asociativos
 * y / o numericos.
 * @param Char $tipoResp caracter que define el tipo de la respuesta, pueden ser [A=Asociativo (por defecto), N= Numerico]
 */
    public function Fetch($tipoResp="A"){
// Validaciones básicas
        if (!Core::ValidacionBasica($this->resultado,1)) {//Validamos que haya previamente una consulta.
            return Core::MsgError("Error, para poder usar el metodo 'Fetch()'"
                ." debe haber realizado una consulta con el metodo 'Query()' "
                ."previamente.");
        }// si no se cumple este error continuamos la ejecusion del codigo.
        if (!Core::ValidacionBasica($tipoResp)) {
            return Core::MsgError("Error, en el metodo 'Fetch()' el parametro "
            ."'\$tipoResp' no puede definirse vacio. Las Opciones para la "
            ."definicion de este parametro son los caracteres 'A', 'N' y 'O', "
            ."donde 'A' indica al metodo que la respuesta debe ser un array Asociativo, "
            ."'N' indica que debe ser un array Numerico y 'O' que debe ser de Objetos.");
        }// si no se cumple este error continuamos la ejecusion del codigo.

        if ($tipoResp=="A" || $tipoResp=="a") {
            $array=$this->resultado->fetch_array(MYSQLI_ASSOC);
            $this->resultado->close();
            return $array;
        }elseif ($tipoResp=="N" || $tipoResp=="n") {
            $array=$this->resultado->fetch_array(MYSQLI_NUM);
            $this->resultado->close();
            return $array;
        }elseif ($tipoResp=="O" || $tipoResp=="o") {
            echo "Deshabilitado temporalmente.";
            $this->resultado->close();
            return false;
        }else {
            return Core::MsgError("Error, en el metodo 'Fetch()' el parametro "
            ."'\$tipoResp' solo puede contener uno de las tres (3) caracteres"
            ." permitidos: [A(asociativo),N(numerico),O(objeto)]");
        }

    }// Fin del Metodo

public function Query ($sql)
	{
	/*if (!Core::ValidacionBasica($sql)) {
            return Core::MsgError("Error, en el metodo 'Fetch()' el parametro "
            ."'\$query' no puede definirse vacio.");
        }// si no se cumple este error continuamos la ejecusion del codigo.
*/

     // Para determinar el sumero de consultas que ha realizado el objeto.
    $this->querys++;
     // Borrando espacios blancos y caracteres de saltos antes al principio y final de la cadena.
    $sql=trim($sql);

    // $sql = mysql_real_escape_string($sql);
    // Al parecer es mas eficiente usarlo sobre variables especificas o
    // datos provenientes de campos formularios.

    // Escapando Comillas en caso que el servidor tenga deshabilitado el escape automatico.
    if (!get_magic_quotes_gpc()) {// si el servidor no escapa automaticamente los slashes
      $sql= addslashes($sql);
      }

    if ($resultado_auxiliar=$this->punteroBD->query($sql)) {
        $this->resultado=$resultado_auxiliar;
        return $this->resultado;
    }else {
        return Core::MsgError("Error, no se pudo procesar su consulta en la "
            ."Base de Datos. "
            ."Mensaje de MySQL: ".$this->punteroBD->errno." - ".$this->punteroBD->error);
    }
}// Fin del metodo

/**
 * Devuelve el numero total de filas o registros obtenidos en la consulta mas reciente
 * de la tabla pasada como parametro, o la ultima tabla afectada en caso de no haber definido tal
 * parametro. En caso de no existir la tabla o de ocurrir un error, se devuelve
 * una cadena de explicacion.
 * @param string $nombreTabla define el nombre de la tabla sobre la cual se desea obtener el numero de filas o registros.
 * @return Integer
 */
public function NumFilas($nombreTabla="Default"){
    // Validaciones básicas
        if (!Core::ValidacionBasica($nombreTabla)) {
        return Core::MsgError("Error, el metodo 'NumFilas()' debe poseer un parametro valido."
            ." Si UD. invoca el metodo sin pasar un atributo, obtendrá "
            ."los resultados en base a la tabla afectada en la ultima consulta realizada por el objeto.");
    }elseif ($nombreTabla=="Default") {
        if (!Core::ValidacionBasica($this->resultado,1)) {//Validamos que haya previamente una consulta.
            return Core::MsgError("Error, para poder usar el metodo 'NumFilas()'"
                ." debe haber realizado una consulta con el metodo 'Query()' "
                ."previamente, O invocar el metodo indicando el nombre de la tabla como parametro.");
                }
        $this->numFilas=$this->resultado->num_rows;
        return $this->numFilas;
    }else {
        $sql_auxiliar="SELECT * FROM $nombreTabla";
        if ($resultado_auxiliar=$this->Query($sql_auxiliar)) {
            $this->numFilas=$resultado_auxiliar->num_rows;
            return $this->numFilas;
        }else {
            return Core::MsgError("Error, la tabla '$nombreTabla' pasada como "
                ."parametro al metodo 'NumFilas()' no existe. "
                ."Mensaje de MySQL: ".$this->punteroBD->errno." - ".$this->punteroBD->error);
        }
    }
        
}

/**
 * Devuelve el numero de columnas o campos de la tabla pasada como
 * parametro o la ultima tabla consultada en caso de no haber definido tal
 * parametro. En caso de no existir la tabla o de ocurrir un error, se devuelve
 * una cadena de explicacion.
 * @param string $nombreTabla define el nombre de la tabla sobre la cual se desea obtener el numero de columnas o campos.
 * @return Integer Representa el numero de columnas contenidas en la tabla de la ultima consulta realizada.
 */
public function NumColumnas($nombreTabla="Default"){
    // Validaciones básicas
        if (!Core::ValidacionBasica($nombreTabla)) {
        return Core::MsgError("Error, el metodo 'NumColumnas()' debe poseer un parametro valido."
            ." Si UD. invoca el metodo sin pasar un atributo, obtendrá "
            ."los resultados en base a la tabla afectada en la ultima consulta realizada por el objeto.");
    }elseif ($nombreTabla=="Default") {
        if (!Core::ValidacionBasica($this->resultado)) {//Validamos que haya previamente una consulta.
            return Core::MsgError("Error, para poder usar el metodo 'NumColumnas()'"
                ." debe haber realizado una consulta con el metodo 'Query()' "
                ."previamente, O invocar el metodo indicando el nombre de la tabla como parametro.");
                }
        $this->numColumnas=$this->resultado->field_count;
        return $this->numColumnas;
    }else {
        $sql_auxiliar="SELECT * FROM $nombreTabla";
        if ($resultado_auxiliar=$this->Query($sql_auxiliar)) {
            $this->numColumnas=$this->resultado->field_count;
            return $this->numColumnas;
        }else {
            return Core::MsgError("Error, la tabla '$nombreTabla' pasada como "
                ."parametro al metodo 'NumColumnas()' no existe. "
                ."Mensaje de MySQL: ".$this->punteroBD->errno." - ".$this->punteroBD->error);
        }
    }

}// Fin de Metodo

/**
 * Devuelve una Matriz de Objetos con los matedatos de la tabla pasada como
 * parametro o la ultima tabla consultada en caso de no haber definido tal
 * parametro. En caso de no existir la tabla o de ocurrir un error, se devuelve
 * una cadena de explicacion.
 * @param string $nombreTabla define el nombre de la tabla sobre la cual se desean obtener sus metadatos.
 * @return array contiene los objetos.
 */
public function FetchFields($nombreTabla="Default"){
    if (!Core::ValidacionBasica($nombreTabla)) {
        return Core::MsgError("Error, el metodo 'FetchFields()' debe poseer un parametro valido."
            ." Si UD. invoca el metodo sin pasar un atributo, obtendrá "
            ."los resultados en base a la ultima tabla afectada en una consulta.");
    }elseif ($nombreTabla=="Default") {
        if (!Core::ValidacionBasica($this->resultado,1)) {//Validamos que haya previamente una consulta.
            return Core::MsgError("Error, para poder usar el metodo 'FetchFields()'"
                ." debe haber realizado una consulta con el metodo 'Query()' "
                ."previamente. O invocar el metodo indicando el nombre de la tabla como parametro.");
                }
        $matrizMetadatosColumnas=$this->resultado->fetch_fields();
        return $matrizMetadatosColumnas;
    }else {
        $sql_auxiliar="SELECT * FROM $nombreTabla";
        if ($resultado_auxiliar=$this->Query($sql_auxiliar)) {
            $matrizMetadatosColumnas=$resultado_auxiliar->fetch_fields();
            return $matrizMetadatosColumnas;
        }else {
            return Core::MsgError("Error, la tabla '$nombreTabla' pasada como "
                ."parametro al metodo 'FetchFields()' no existe. "
                ."Mensaje de MySQL: ".$this->punteroBD->errno." - ".$this->punteroBD->error);
        }
    }
}// Fin de Metodo

public function Prepare($parametros){
    // d: double - s: string - i: integer - b:blob

    $ParametrosPasados=func_get_args();
    $NumParametros = func_num_args();
    $NumExtras=$NumParametros-1;
    $sql=$ParametrosPasados[0];


    if (!Core::ValidacionBasica($sql)) {
        return Core::MsgError("Error, el metodo 'Prepare()' requiere que el parametro introducido sea valido.");
    }
// trabajo con los paramentros pasados al metodo
echo "antes del metodo stmt_init()";
if (!$this->stmt_init()) {
     return Core::MsgError("Error al invocar stmt_init()");
    }
    echo "despues del metodo stmt_init()";
    if ($this->stmt_init->prepare($sql)) {
            for($i=1;$i<$NumParametros;$i++){
                echo "Dentro del For";
                $ParamListos=explode(':', $ParametrosPasados[$i]);
                $this->stmt_init->bind_param($ParamListos[0],$ParamListos[1]);
                echo("<br>bind_param(".$ParamListos[0].",".$ParamListos[1].")<br>");
            }
        }else {
            echo("error");
    }

echo "Finalizado";
}



}// Fin de la clase
?>